package com.numone.testble.ble;

import android.app.Application;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.Build;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import android.util.Log;

import com.numone.testble.App;

import java.lang.reflect.Method;
import java.util.Set;
import java.util.concurrent.TimeoutException;

public class BleConnectPresenter {

    private ConnectHandler connectHandler;
    public final static int H_BOND_STATE_CHANGED = 0x01;
    public final static int H_BOND_CONNECT_TIME_OUT = 0x02;

    public BleConnectPresenter(){
        connectHandler = new ConnectHandler(Looper.getMainLooper());
    }

    /**
     * 获取已连接设备
     * @return
     */
    public BluetoothDevice getConnectedBle(){
        Set<BluetoothDevice> devices = BluetoothAdapter.getDefaultAdapter().getBondedDevices();
        if(devices != null && !devices.isEmpty()){
            for(BluetoothDevice device : devices){
                try {
                    Method isConnectedMethod = BluetoothDevice.class.getDeclaredMethod("isConnected", (Class[]) null);
                    isConnectedMethod.setAccessible(true);//打开权限
                    boolean isConnected = (boolean) isConnectedMethod.invoke(device, (Object[]) null);
                    if(isConnected){
                        Log.d("ConnectedBle","ConnectedBle="+device.getName()+" mac="+device.getAddress());
                        return device;
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }
        return null;
    }

    /**
     * 取消所有配对
     */
    public void removeBondAllDevice(){
        Set<BluetoothDevice> devices = BluetoothAdapter.getDefaultAdapter().getBondedDevices();
        if(devices != null && !devices.isEmpty()){
            for(BluetoothDevice device : devices){
                try {
                    Method isConnectedMethod = BluetoothDevice.class.getDeclaredMethod("isConnected", (Class[]) null);
                    isConnectedMethod.setAccessible(true);//打开权限
                    boolean isConnected = (boolean) isConnectedMethod.invoke(device, (Object[]) null);
                    if(isConnected){
                        removeBond(device);
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }
    }

    public void connectBle(String mac){
        createBond(mac);
    }

    /**
     * 开始配对
     * @param mac
     */
    public void createBond(String mac){
        BluetoothDevice device = BluetoothAdapter.getDefaultAdapter().getRemoteDevice(mac);
        if(device.getBondState() == BluetoothDevice.BOND_BONDED){
            //配对
            removeBond(device);
        }
        //注册广播
        registerConnectBroadcast();
        try {
            //创建createBond
//            BleClsUtils.createBond(device.getClass(), device);
            device.createBond();
            if(null != onConnectCallBack){
                onConnectCallBack.onStartConnect(device);
            }
            connectHandler.sendEmptyMessageDelayed(H_BOND_CONNECT_TIME_OUT,3000);
        } catch (Exception e) {
            e.printStackTrace();
            unregisterConnectBroadcast();
            if(null != onConnectCallBack){
                onConnectCallBack.onConnectFail(device,e);
            }
        }
    }

    private ConnectBroadcastReceiver connectBroadcastReceiver;
    /**
     * 监听配对状态
     */
    public synchronized void registerConnectBroadcast() {
        Application application = App.getApp();
        //注册蓝牙开关状态广播接收者
        if (connectBroadcastReceiver == null && application != null) {
            connectBroadcastReceiver = new ConnectBroadcastReceiver();
            IntentFilter filter = new IntentFilter();
            //已连接
            filter.addAction(BluetoothDevice.ACTION_ACL_CONNECTED);
            //连接断开
            filter.addAction(BluetoothDevice.ACTION_ACL_DISCONNECTED);
            //配对状态改变
            filter.addAction(BluetoothDevice.ACTION_BOND_STATE_CHANGED);
            //配对请求，也就系统弹窗提示是否进行配对
            filter.addAction(BluetoothDevice.ACTION_PAIRING_REQUEST);
            application.registerReceiver(connectBroadcastReceiver, filter);
        }
    }

    /**
     * 解注册
     */
    public void unregisterConnectBroadcast(){
        try{
            if(null != App.getApp() && null != connectBroadcastReceiver){
                App.getApp().unregisterReceiver(connectBroadcastReceiver);
                connectBroadcastReceiver = null;
            }
        }catch (Exception e){
            e.printStackTrace();
        }
    }

    private class ConnectBroadcastReceiver extends BroadcastReceiver {
        @Override
        public void onReceive(Context context, Intent intent) {
            Log.e("BluetoothConnect","intent="+intent.toString());
            String action = intent.getAction();
            if (action != null) {
                BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
                switch (action) {
                    case BluetoothDevice.ACTION_ACL_CONNECTED:{
                        Log.d("BluetoothConnect","已连接");
                        break;
                    }
                    case BluetoothDevice.ACTION_ACL_DISCONNECTED:{
                        Log.d("BluetoothConnect","断开连接");
                        break;
                    }
                    case BluetoothDevice.ACTION_BOND_STATE_CHANGED:
                        Log.d("BluetoothConnect","配对状态改变");
                        if (device != null) {
                            connectHandler.removeMessages(H_BOND_CONNECT_TIME_OUT);
                            int key = intent.getExtras().getInt(BluetoothDevice.EXTRA_PAIRING_KEY,-1);
                            int VARIANT = intent.getExtras().getInt(BluetoothDevice.EXTRA_PAIRING_VARIANT,-1);
                            int BOND_STATE = intent.getExtras().getInt(BluetoothDevice.EXTRA_PREVIOUS_BOND_STATE,-1);
                            String tt = "  key="+key+" VARIANT="+VARIANT+" BOND_STATE="+BOND_STATE;
                            Log.e("BluetoothConnect","BOND_STATE_CHANGED = "+device.getBondState()+tt);

                            if(device.getBondState() == BluetoothDevice.BOND_NONE){
                                Log.d("BluetoothConnect","配对失败");
                            }
                            else if(device.getBondState() == BluetoothDevice.BOND_BONDING){
                                Log.d("BluetoothConnect","配对中");
                            }
                            else if(device.getBondState() == BluetoothDevice.BOND_BONDED){
                                Log.d("BluetoothConnect","配对成功");
                            }
                            Message message = Message.obtain();
                            message.what = H_BOND_STATE_CHANGED;
                            message.obj = device;
                            message.arg1 = device.getBondState();
                            connectHandler.sendMessage(message);
                        }
                        break;

                    case BluetoothDevice.ACTION_PAIRING_REQUEST:{
                        //配对的验证码，如果是-1侧不需要验证码
                        int key = intent.getExtras().getInt(BluetoothDevice.EXTRA_PAIRING_KEY,-1);
                        int VARIANT = intent.getExtras().getInt(BluetoothDevice.EXTRA_PAIRING_VARIANT,-1);
                        int BOND_STATE = intent.getExtras().getInt(BluetoothDevice.EXTRA_PREVIOUS_BOND_STATE,-1);
                        String tt = "  key="+key+" VARIANT="+VARIANT+" BOND_STATE="+BOND_STATE;
                        Log.d("BluetoothConnect","getBondState = "+device.getBondState()+tt);
                        if (device.getBondState() != BluetoothDevice.BOND_BONDED) {
                            try {
                                /**
                                 * cancelPairingUserInput（）取消用户输入密钥框，
                                 * 个人觉得一般情况下不要和setPin（setPasskey、setPairingConfirmation、
                                 * setRemoteOutOfBandData）一起用，
                                 * 这几个方法都会remove掉map里面的key:value（<<<<<也就是互斥的>>>>>>）。
                                 */
                                //1.确认配对
                                boolean success = false;
                                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
                                    if(key != -1){
                                        success = device.setPin(String.valueOf(key).getBytes());
                                    }else {
                                        //需要系统权限，如果没有系统权限，就点击弹窗上的按钮配对吧
                                        success = device.setPairingConfirmation(true);
                                    }
                                }
                                Log.d("BluetoothConnect","key="+key+"  bond="+success);
                                //如果没有将广播终止，则会出现一个一闪而过的配对框。
                                abortBroadcast();
                            } catch (Exception e) {
                                Log.e("BluetoothConnect","反射异常："+e);
                            }
                        }
                        break;
                    }
                }
            }
        }
    }

    public void removeBond(BluetoothDevice device){
        try {
            if(null != device){
                 BleClsUtils.removeBond(device.getClass(), device);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    private OnConnectCallBack onConnectCallBack;

    public void setOnConnectCallBack(OnConnectCallBack onConnectCallBack) {
        this.onConnectCallBack = onConnectCallBack;
    }

    public interface OnConnectCallBack{
        void onStartConnect(BluetoothDevice bleDevice);

        void onConnectFail(BluetoothDevice bleDevice, Exception e);

        void onConnectSuccess(BluetoothDevice bleDevice);

        void onDisConnected(BluetoothDevice bleDevice);
    }

    private final class ConnectHandler extends Handler {

        ConnectHandler(Looper looper) {
            super(looper);
        }

        @Override
        public void handleMessage(Message msg) {
            Log.e("BluetoothHandler","Message="+msg.toString());
            switch (msg.what) {
                case H_BOND_STATE_CHANGED:{
                    int getBondState = msg.arg1;
                    if(getBondState == BluetoothDevice.BOND_BONDED){
                        if(null != onConnectCallBack){
                            onConnectCallBack.onConnectSuccess((BluetoothDevice)msg.obj);
                        }
                    }
                    else if(getBondState == BluetoothDevice.BOND_NONE){
                        if(null != onConnectCallBack){
                            onConnectCallBack.onConnectFail((BluetoothDevice)msg.obj,null);
                        }
                    }
                    break;
                }
                case H_BOND_CONNECT_TIME_OUT:{
                    if(null != onConnectCallBack){
                        onConnectCallBack.onConnectFail(null,new TimeoutException());
                    }
                    break;
                }
            }
        }
    }
}
